/**
  ******************************************************************************
  * @file           : MMC5983.c
  * @author         : lengq
  * @brief          : 地磁传感器驱动
  * @attention      : 校准以及数据采集功能，采集范围+-8g(高斯)
  * @date           : 2024/4/8
  ******************************************************************************
  */


#include <math.h>
#include "MMC5983.h"

static stc_mmc5983_t mmc5983;
mmc5983_callback_t mmc5983_cbs;

void mmc_sda_pin_set(uint8_t sta)
{
	if(sta == IIC_HIGH)
		MAG_SDA_HIGH();
	else
		MAG_SDA_LOW();
}

void mmc_scl_pin_set(uint8_t sta)
{
	if(sta == IIC_HIGH)
		MAG_SCL_HIGH();
	else
		MAG_SCL_LOW();
}

uint8_t mmc_sda_pin_get(void)
{
	uint8_t r_data = 0;
	
	r_data = MAG_SDA_GET();
	
	return r_data;
}

void mmc_sda_pin_dir(uint8_t dir)
{
	if(dir == SDA_OUT)
		MAG_SDA_OUT();
	else
		MAG_SDA_IN();
}

stc_soft_iic_t mmc_iic_t = 
{
	.sda_pin_set = mmc_sda_pin_set,
	.scl_pin_set = mmc_scl_pin_set,
	.sda_pin_get = mmc_sda_pin_get,
	.sda_pin_dir = mmc_sda_pin_dir,
	.delay_us    = hdl_delay_us,
};


/**
 * 初始化MMC5983
 */
//最大值 X,Y,Z
static int32_t max_in[XYZ];
//最小值 X,Y,Z
static int32_t min_in[XYZ];
//当前数据存放结构体
static MMC5983Var_t MMC5983Var;

/*****************************************************************************************
* 函数名称: MMC5983_Write_Reg
* 功能描述: MMC5983写寄存器
* 参    数: reg 寄存器地址
						val 寄存器数据
* 返 回 值: 成功返回true，失败返回false
*****************************************************************************************/
static bool MMC5983_Write_Reg(uint8_t reg, uint8_t val) 
{
    hdl_iic_master_write(&mmc_iic_t, 0x60, reg, &val, 1);
	return RT_TRUE;
}


/*****************************************************************************************
* 函数名称: MMC5983_Read_Reg
* 功能描述: MMC5983读寄存器
* 参    数: reg 寄存器地址
* 返 回 值: 返回寄存器值
*****************************************************************************************/
static uint8_t MMC5983_Read_Reg(uint8_t reg) 
{
    return hdl_iic_master_read_byte(&mmc_iic_t, 0x60, reg);
}

/*****************************************************************************************
* 函数名称: MMC5983_Read_Buffer
* 功能描述: MMC5983读数据
* 参    数: reg 寄存器地址
						buffer 读取数据输出缓存入口
						len 读取长度
* 返 回 值: 成功返回true，失败返回false
*****************************************************************************************/
static bool MMC5983_Read_Buffer(uint8_t reg, void *buffer, uint8_t len) {
    hdl_iic_master_read(&mmc_iic_t, 0x60, reg, buffer, len);
	return RT_TRUE;
}

int mmc5983_init(void) 
{
    uint8_t id = 0;
    rt_thread_mdelay(10);
	
	mmc5983_cbs = 0;

    id = MMC5983_Read_Reg(MMC5983_ID);
    rt_kprintf("MMC5983 id=0x%x\r\n", id);
    if (id != 0x30) {
        rt_kprintf("MMC5983 INIT Err...\r\n");
        return 0;
    }
    //设备进行set
    MMC5983_Write_Reg(MMC5983_CTRL_0, 0x09);
    rt_thread_mdelay(1);
    //设备进行reset
    MMC5983_Write_Reg(MMC5983_CTRL_0, 0x10);
    rt_thread_mdelay(1);

    LeftMMC5983RegCtrl0 Ctrl0Reg;
    Ctrl0Reg.Byte = 0x00;
    //重新读取otp内的数据
    Ctrl0Reg.Bit.Set = 1;
    MMC5983_Write_Reg(MMC5983_CTRL_0, Ctrl0Reg.Byte);

    //重启地磁传感器
    LeftMMC5983RegCtrl1 Ctrl1Reg;
    Ctrl1Reg.Byte = 0x00;
    Ctrl1Reg.Bit.SW_RST = 1;
    MMC5983_Write_Reg(MMC5983_CTRL_1, Ctrl1Reg.Byte);
    rt_thread_mdelay(10);//延时10ms,等待芯片重启完成

    LeftMMC5983RegCtrl2 Ctrl2Reg;        //关闭连续转换
    Ctrl2Reg.Byte = 0x00;
    Ctrl2Reg.Bit.Cm_freq = 7;
    Ctrl2Reg.Bit.Cmm_en = 1;
    Ctrl2Reg.Bit.Prd_set = 7;
    Ctrl2Reg.Bit.En_prd_set = 1;
    MMC5983_Write_Reg(MMC5983_CTRL_2, Ctrl2Reg.Byte);

    LeftMMC5983RegCtrl3 Ctrl3Reg;
    Ctrl3Reg.Byte = 0x00;
    Ctrl3Reg.Bit.St_enm = 1;
    Ctrl3Reg.Bit.St_enp = 1;
    MMC5983_Write_Reg(MMC5983_CTRL_3, Ctrl3Reg.Byte);

    LeftMMC5983RegCtrl0 Ctrl0_Reg;
    Ctrl0_Reg.Byte = 0x00;
    Ctrl0_Reg.Bit.Auto_SR_en = 1;
    //开启磁场测量
    Ctrl0_Reg.Bit.TM_M = 1;
    MMC5983_Write_Reg(MMC5983_CTRL_0, Ctrl0_Reg.Byte);
    //rt_thread_mdelay(10);
    //MMC5983StartCov();

    rt_kprintf("MMC5983 INIT OK...\r\n");
    return 0;
}


/*****************************************************************************************
* 函数名称: MMC5983_Read
* 功能描述: MMC5983读取原始数据
* 参    数: MagAdcX X轴数据
				MagAdcY Y轴数据
				MagAdcZ Z轴数据
* 返 回 值: 成功返回true，失败返回false
*****************************************************************************************/
static bool MMC5983_Read(uint32_t *buf)
{
	uint8_t buff[7] = {0};
	
    //发送开始采集指令以及set指令
    MMC5983_Write_Reg(MMC5983_CTRL_0, 0x09);
    //发送开始采集指令
    MMC5983_Write_Reg(MMC5983_CTRL_0, 0x01);
    //等待数据采集完成
    rt_thread_delay(1);
    
    //发送读取数据指令
    if (MMC5983_Read_Buffer(MMC5983_X_OUT_H, buff, 7) == false)
        return RT_FALSE;
    //数据复制
	// Turn the 18 bits into unsigned 32-bit value
    buf[0] = (uint32_t) (buff[0] << 10 | buff[1] << 2 | (buff[6] & 0xC0) >> 6);
    buf[1] = (uint32_t) (buff[2] << 10 | buff[3] << 2 | (buff[6] & 0x30) >> 4);
    buf[2] = (uint32_t) (buff[4] << 10 | buff[5] << 2 | (buff[6] & 0x0C) >> 2);
	
    return RT_TRUE;
}

/*****************************************************************************************
* 函数名称: Mag_Calib_XYZ
* 功能描述: 获取XY轴极值
* 参    数: magrefX x轴采样数据
						magrefY y轴采样数据
* 返 回 值: 无
*****************************************************************************************/
static void Mag_Calib_XYZ(int32_t magrefX, int32_t magrefY, int32_t magrefZ) {
    max_in[X] = MAX(max_in[X], magrefX);
    min_in[X] = MIN(min_in[X], magrefX);
    max_in[Y] = MAX(max_in[Y], magrefY);
    min_in[Y] = MIN(min_in[Y], magrefY);
    max_in[Z] = MAX(max_in[Z], magrefZ);
    min_in[Z] = MIN(min_in[Z], magrefZ);
}

//静态软件定时器
struct rt_timer mmc5983_timer = {0};

/**
 * MMC5983校准 外部调用开始校准，需要旋转30s
 */
void MMC5983Calib(void) {
    MMC5983Var.CalibStatus = RT_TRUE;
    //恢复默认值
    MMC5983Var.Mag_Reference_Val[X] = 0;
    MMC5983Var.Mag_Reference_Val[Y] = 0;
    MMC5983Var.Mag_Reference_Val[Z] = 0;
    //恢复默认比例值
    MMC5983Var.Mag_Reference_K[X] = 1.0f;
    MMC5983Var.Mag_Reference_K[Y] = 1.0f;
    MMC5983Var.Mag_Reference_K[Z] = 1.0f;

    for (int i = 0; i < 3; i++) {
//        max_in[i] = -131072;
//        min_in[i] = 131072;
        max_in[i] = 0;
        min_in[i] = 0;
    }
    //启动定时器
    rt_timer_start(&mmc5983_timer);
}

void MMC5983Calib_callback(void) {
    MMC5983Var.Mag_Reference_Val[X] = (max_in[X] + min_in[X]) / 2;
    MMC5983Var.Mag_Reference_Val[Y] = (max_in[Y] + min_in[Y]) / 2;
    MMC5983Var.Mag_Reference_Val[Z] = (max_in[Z] + min_in[Z]) / 2;
    rt_kprintf("MMC5983Calib_callback:X=%d,Y=%d,Z=%d\r\n", MMC5983Var.Mag_Reference_Val[X],
               MMC5983Var.Mag_Reference_Val[Y], MMC5983Var.Mag_Reference_Val[Z]);
    //计算比例值
    MMC5983Var.Mag_Reference_K[X] = 2.0f / (float) (max_in[X] - min_in[X]);
    MMC5983Var.Mag_Reference_K[Y] = 2.0f / (float) (max_in[Y] - min_in[Y]);
    MMC5983Var.Mag_Reference_K[Z] = 2.0f / (float) (max_in[Z] - min_in[Z]);
    //关闭校准状态
    MMC5983Var.CalibStatus = RT_FALSE;
}

static void mmc5983_timer_callback(void *parameter) {
    rt_kprintf("MMC5983 timer callback...\r\n");
    //关闭定时器
    rt_timer_stop(&mmc5983_timer);
    //校准完成回调
    MMC5983Calib_callback();
    //发送校准完成标志
//    MyLpUart_SendString("MMC5983_Calib_complete\r\n");
}


//void MMC5983_thread_entry(void *parameter)
//{
//	uint32_t mag_buf[3] = {0};
//	
//    MMC5983_Init();
//    //定时器初始化为软件定时器 10秒进行校准时间
//    rt_timer_init(&mmc5983_timer, "mmc5983_timer", mmc5983_timer_callback, RT_NULL, 10000, RT_TIMER_FLAG_SOFT_TIMER);
//    MMC5983Var.Mag_Reference_K[X] = 1.0f;
//    MMC5983Var.Mag_Reference_K[Y] = 1.0f;
//    MMC5983Var.Mag_Reference_K[Z] = 1.0f;

//    for (;;) {

//        //读取数据
//        MMC5983_Read(mag_buf);

//		mmc5983.mag_x = (((float)mag_buf[0] - 131072.0f) / 131072.0f) * 8 * 1000;
//		mmc5983.mag_y = (((float)mag_buf[1] - 131072.0f) / 131072.0f) * 8 * 1000;
//		mmc5983.mag_z = (((float)mag_buf[2] - 131072.0f) / 131072.0f) * 8 * 1000;

//        ///校准检测
//        //校准状态
//        if (MMC5983Var.CalibStatus == TRUE) {
//            //地磁传感器数据比较
//            Mag_Calib_XYZ(MagAdcX, MagAdcY, MagAdcZ);
//        } else {
//            //发送采集完成标志
//            rt_event_send(&event, (1 << 3));
//        }
//        rt_thread_delay(100);
//    }

//}

void mmc5983_proc(void)
{
	uint32_t mag_buf[3] = {0};
	
	switch(mmc5983.step)
	{
		case MMC5983_IDLE:
			break;
		case MMC5983_INIT:
			break;
		case MMC5983_START:
			break;
		case MMC5983_READ:
			//读取数据
			MMC5983_Read(mag_buf);

			mmc5983.mag_x = (((float)mag_buf[0] - 131072.0f) / 131072.0f) * 8 * 1000;
			mmc5983.mag_y = (((float)mag_buf[1] - 131072.0f) / 131072.0f) * 8 * 1000;
			mmc5983.mag_z = (((float)mag_buf[2] - 131072.0f) / 131072.0f) * 8 * 1000;
		
			if(mmc5983_cbs)
			{
				mmc5983_cbs(mmc5983);
			}
			break;
		default:
			break;
	}
}

void mmc5983_callback_cbs_register(mmc5983_callback_t pCBS)
{
	if(mmc5983_cbs == 0)
	{
		mmc5983_cbs = pCBS;
	}
}

void mmc5983_start(void)
{
	mmc5983.step = MMC5983_READ;
}

